1
|
|
|
/** global: UB */ |
2
|
|
|
|
3
|
|
|
var stringFuncs = { |
4
|
|
|
|
5
|
|
|
|
6
|
|
|
// primary search functions |
7
|
|
|
indexOf: function(search, startAt = null){ |
8
|
|
|
return this.smartIndexOf(search, true, true, startAt); |
9
|
|
|
}, |
10
|
|
|
indexOfCI: function(search, startAt = null){ |
11
|
|
|
return this.smartIndexOf(search, false, true, startAt); |
12
|
|
|
}, |
13
|
|
|
smartIndexOf: function(search, caseSensitive = true, first = true, startAt = null, substringIsLower = false, wholeWords = false){ |
14
|
|
|
var text = this; |
15
|
|
|
|
16
|
|
|
// temps |
17
|
|
|
var sl = search.length; |
18
|
|
|
var ml = (text.length - sl); |
19
|
|
|
|
20
|
|
|
// quick checks |
21
|
|
|
if (ml < sl) { |
22
|
|
|
return -1; |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
// only check equality of both strings of equal length |
26
|
|
|
if (ml == sl) { |
27
|
|
|
if (caseSensitive && !wholeWords) { |
28
|
|
|
return (text == search) ? 0 : -1; |
29
|
|
|
} |
30
|
|
|
return text.isEqual(search, caseSensitive, false, substringIsLower) ? 0 : -1; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
|
34
|
|
|
// default start at |
35
|
|
|
if (first) { |
36
|
|
|
if (startAt == null) { |
37
|
|
|
startAt = 0; |
38
|
|
|
} |
39
|
|
|
} else { |
40
|
|
|
if (startAt == null) { |
41
|
|
|
startAt = ml - sl; |
42
|
|
|
} |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
|
46
|
|
|
// if using whole words, slower version is used |
47
|
|
|
if (wholeWords) { |
48
|
|
|
var regex = UB.regex.New(search, wholeWords, caseSensitive, true); |
49
|
|
|
if (first) { |
50
|
|
|
var i = startAt === 0 ? text.search(regex) : text.substring(startAt).search(regex); |
51
|
|
|
} else { |
52
|
|
|
/*var i:int = startAt == (ml - sl) ? text.search(regex) : text.substring(startAt).search(regex);*/ |
53
|
|
|
/// unsupported |
54
|
|
|
i = -1; |
55
|
|
|
} |
56
|
|
|
return i; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
|
60
|
|
|
|
61
|
|
|
if (first) { |
62
|
|
|
|
63
|
|
|
// FIRST INDEX |
64
|
|
|
|
65
|
|
|
// CASE INSENSITIVE |
66
|
|
|
if (!caseSensitive) { |
67
|
|
|
|
68
|
|
|
// very fast CI comparison |
69
|
|
|
return text._indexOfCI(search, startAt, substringIsLower, sl, ml); |
70
|
|
|
|
71
|
|
|
// much faster than this: |
72
|
|
|
//return text.toUpperCase().indexOf(search.toUpperCase(), startAt); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
// CASE SENSITIVE |
76
|
|
|
return text.indexOf(search, startAt); |
77
|
|
|
|
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
|
81
|
|
|
// LAST INDEX |
82
|
|
|
|
83
|
|
|
// CASE INSENSITIVE |
84
|
|
|
if (!caseSensitive) { |
85
|
|
|
|
86
|
|
|
// very fast CI comparison |
87
|
|
|
return text._lastIndexOfCI(search, startAt, substringIsLower, sl); |
88
|
|
|
|
89
|
|
|
// much faster than this: |
90
|
|
|
//return text.toUpperCase().lastIndexOf(search.toUpperCase(), startAt); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
// CASE SENSITIVE |
94
|
|
|
return text.lastIndexOf(search, startAt); |
95
|
|
|
}, |
96
|
|
|
|
97
|
|
View Code Duplication |
_indexOfCI: function(search, startAt, substringIsLower, sl, ml){ |
|
|
|
|
98
|
|
|
var text = this; |
99
|
|
|
|
100
|
|
|
// init casing tables |
101
|
|
|
if (UB.UTF_lowerToUpper == null){ |
102
|
|
|
UB.initCasing(); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
// per main char |
106
|
|
|
for (var m = startAt;m <= ml;m++){ |
107
|
|
|
|
108
|
|
|
|
109
|
|
|
// per substring char |
110
|
|
|
var match = true; |
111
|
|
|
for (var s = 0;s<sl;s++){ |
112
|
|
|
|
113
|
|
|
var c1 = text.charCodeAt(m + s); |
114
|
|
|
var c2 = search.charCodeAt(s); |
115
|
|
|
|
116
|
|
|
// CI |
117
|
|
|
if (c1 <= UB.UTF_casingTablesMax){ /// CI |
118
|
|
|
c1 = UB.UTF_upperToLower[c1]; |
119
|
|
|
} |
120
|
|
|
if (!substringIsLower){ |
121
|
|
|
if (c2 <= UB.UTF_casingTablesMax){ /// CI |
122
|
|
|
c2 = UB.UTF_upperToLower[c2]; |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
if (c1 != c2) { |
127
|
|
|
match = false; |
128
|
|
|
break; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
if (match){ |
134
|
|
|
return m; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return -1; |
140
|
|
|
}, |
141
|
|
|
|
142
|
|
View Code Duplication |
_lastIndexOfCI: function(search, startAt, substringIsLower, sl){ |
|
|
|
|
143
|
|
|
var text = this; |
144
|
|
|
|
145
|
|
|
// init casing tables |
146
|
|
|
if (UB.UTF_lowerToUpper == null){ |
147
|
|
|
UB.initCasing(); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
// per main char |
151
|
|
|
for (var m = startAt;m >= 0;m--){ |
152
|
|
|
|
153
|
|
|
|
154
|
|
|
// per substring char |
155
|
|
|
match = true; |
|
|
|
|
156
|
|
|
for (var s = 0;s<sl;s++){ |
157
|
|
|
|
158
|
|
|
c1 = text.charCodeAt(m + s); |
|
|
|
|
159
|
|
|
c2 = search.charCodeAt(s); |
|
|
|
|
160
|
|
|
|
161
|
|
|
// CI |
162
|
|
|
if (c1 <= UB.UTF_casingTablesMax){ /// CI |
163
|
|
|
c1 = UB.UTF_upperToLower[c1]; |
164
|
|
|
} |
165
|
|
|
if (!substringIsLower){ |
166
|
|
|
if (c2 <= UB.UTF_casingTablesMax){ /// CI |
167
|
|
|
c2 = UB.UTF_upperToLower[c2]; |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
if (c1 != c2) { |
172
|
|
|
match = false; |
173
|
|
|
break; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
if (match){ |
179
|
|
|
return m; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return -1; |
185
|
|
|
}, |
186
|
|
|
|
187
|
|
|
countOf: function(find, caseSensitive = true){ |
188
|
|
|
var text = this; |
189
|
|
|
|
190
|
|
|
// use regex method for case insensitive comparison |
191
|
|
|
if (!caseSensitive){ |
192
|
|
|
var char = UB.regex.Escape(find); |
193
|
|
|
var flags = 'ig'; |
194
|
|
|
return parseInt(text.match(new RegExp(char, flags)).length); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
// use faster method for case sensitive comparison |
198
|
|
|
var count = 0; |
199
|
|
|
var index = 0; |
200
|
|
|
var len = find.length; |
201
|
|
|
while ((index = text.indexOf(find, index)) > -1) { |
202
|
|
|
count++; |
203
|
|
|
index += len; |
204
|
|
|
} |
205
|
|
|
return count; |
206
|
|
|
}, |
207
|
|
|
|
208
|
|
|
/** searches for all the given terms, collects their char indexes (S.IndexOf), and returns the smallest/largest index (depending on `first`) */ |
209
|
|
|
indexOfAny: function(searchFor, first = true, caseSensitive = true, startAt = null){ |
210
|
|
|
var str = this; |
211
|
|
|
|
212
|
|
|
// index of first |
213
|
|
|
if (first) { |
214
|
|
|
return str.indexOfFirstAny(searchFor, caseSensitive, startAt); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
// index of last |
218
|
|
|
if (startAt == null) { |
219
|
|
|
startAt = 0; |
220
|
|
|
} |
221
|
|
|
return str.indexOfLastAny(searchFor, caseSensitive, startAt); |
222
|
|
|
}, |
223
|
|
|
/** searches for all the given terms, collects their char indexes (S.IndexOf), and returns the largest index */ |
224
|
|
|
indexOfLastAny: function(searchFor, caseSensitive = true, startAt = null){ |
225
|
|
|
var str = this; |
226
|
|
|
|
227
|
|
|
// case insensitive if wanted |
228
|
|
|
if (!caseSensitive){ |
229
|
|
|
str = str.toLowerCase(); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
// per search term |
233
|
|
|
var indices = []; |
234
|
|
|
for (var s = 0, sl = searchFor.length;s<sl;s++){ |
235
|
|
|
var sWord = searchFor[s]; |
236
|
|
|
|
237
|
|
|
// case insensitive if wanted |
238
|
|
|
if (!caseSensitive){ |
239
|
|
|
sWord = sWord.toLowerCase(); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
// check where found |
243
|
|
|
indices[s] = str.lastIndexOf(sWord, startAt); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
// return last found term |
247
|
|
|
return indices.max(); |
248
|
|
|
}, |
249
|
|
|
/** searches for all the given terms, collects their char indexes (S.IndexOf), and returns the smallest index */ |
250
|
|
|
indexOfFirstAny: function(searchFor, caseSensitive = true, startAt = 0){ |
251
|
|
|
var str = this; |
252
|
|
|
|
253
|
|
|
// case insensitive if wanted |
254
|
|
|
if (!caseSensitive){ |
255
|
|
|
str = str.toLowerCase(); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
// per search term |
259
|
|
|
var indices = []; |
260
|
|
|
for (var s = 0, sl = searchFor.length;s<sl;s++){ |
261
|
|
|
var sWord = searchFor[s]; |
262
|
|
|
|
263
|
|
|
// case insensitive if wanted |
264
|
|
|
if (!caseSensitive){ |
265
|
|
|
sWord = sWord.toLowerCase(); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
// check where found |
269
|
|
|
indices[s] = str.indexOf(sWord, startAt); |
270
|
|
|
|
271
|
|
|
// change -1 otherwise looks like first found term |
272
|
|
|
if (indices[s] === -1) { |
273
|
|
|
indices[s] = UB.intMaxValue; |
274
|
|
|
} |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
// return first found term |
278
|
|
|
return indices.min(); |
279
|
|
|
}, |
280
|
|
|
endIndexOfLastAny: function(searchFor, caseSensitive = true){ |
281
|
|
|
var str = this; |
282
|
|
|
|
283
|
|
|
// case insensitive if wanted |
284
|
|
|
if (!caseSensitive){ |
285
|
|
|
str = str.toLowerCase(); |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
// per search term |
289
|
|
|
var indices = []; |
290
|
|
|
for (var s = 0, sl = searchFor.length;s<sl;s++){ |
291
|
|
|
var sWord = searchFor[s]; |
292
|
|
|
|
293
|
|
|
// case insensitive if wanted |
294
|
|
|
if (!caseSensitive){ |
295
|
|
|
sWord = sWord.toLowerCase(); |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
// check where found |
299
|
|
|
indices[s] = str.endIndexOfLast(sWord); |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
// return last found term |
303
|
|
|
return indices.max(); |
304
|
|
|
}, |
305
|
|
|
endIndexOfFirstAny: function(searchFor, caseSensitive = true){ |
306
|
|
|
var str = this; |
307
|
|
|
|
308
|
|
|
// case insensitive if wanted |
309
|
|
|
if (!caseSensitive){ |
310
|
|
|
str = str.toLowerCase(); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
// per search term |
314
|
|
|
var indices = []; |
315
|
|
|
for (var s = 0, sl = searchFor.length;s<sl;s++){ |
316
|
|
|
var sWord = searchFor[s]; |
317
|
|
|
|
318
|
|
|
// case insensitive if wanted |
319
|
|
|
if (!caseSensitive){ |
320
|
|
|
sWord = sWord.toLowerCase(); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
// check where found |
324
|
|
|
indices[s] = str.endIndexOfFirst(sWord); |
325
|
|
|
|
326
|
|
|
// change -1 otherwise looks like first found term |
327
|
|
|
if (indices[s] === -1) { |
328
|
|
|
indices[s] = UB.intMaxValue; |
329
|
|
|
} |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
// return first found term |
333
|
|
|
return indices.min(); |
334
|
|
|
}, |
335
|
|
|
endIndexOfFirst: function(find){ |
336
|
|
|
var str = this; |
337
|
|
|
var pos = str.indexOf(find); |
338
|
|
|
if (pos === -1) return -1; |
|
|
|
|
339
|
|
|
return pos + find.length; |
340
|
|
|
}, |
341
|
|
|
endIndexOfLast: function(find){ |
342
|
|
|
var str = this; |
343
|
|
|
var pos = str.lastIndexOf(find); |
344
|
|
|
if (pos === -1) return -1; |
|
|
|
|
345
|
|
|
return pos + find.length; |
346
|
|
|
}, |
347
|
|
|
indexOfNumber: function(startAt = 0, not = false, lenIfNotFound = false){ |
348
|
|
|
var str = this; |
349
|
|
|
for (var c = (startAt>0?startAt:0), cl = str.length;c<cl;c++){ |
350
|
|
|
var char = str.charAt(c); |
351
|
|
|
if (char.isNumber() != not) { |
352
|
|
|
return c; |
353
|
|
|
} |
354
|
|
|
} |
355
|
|
|
return lenIfNotFound ? str.length : -1; |
356
|
|
|
}, |
357
|
|
|
indexOfAlphaNumeric: function(startAt = 0, not = false, lenIfNotFound = false){ |
358
|
|
|
var str = this; |
359
|
|
|
for (var c = (startAt>0?startAt:0), cl = str.length;c<cl;c++){ |
360
|
|
|
var char = str.charAt(c); |
361
|
|
|
if (char.isAlphaNumeric() != not) { |
362
|
|
|
return c; |
363
|
|
|
} |
364
|
|
|
} |
365
|
|
|
return lenIfNotFound ? str.length : -1; |
366
|
|
|
}, |
367
|
|
|
|
368
|
|
|
indexOfMany: function(find, startAt = 0){ |
369
|
|
|
var str = this; |
370
|
|
|
|
371
|
|
|
// returns the index, of the FIRST FOUND item in the string |
372
|
|
|
|
373
|
|
|
var found = -1; |
374
|
|
|
for (var f = 0, fl = find.length;f<fl;f++){ |
375
|
|
|
var at = str.indexOf(find[f], startAt); |
376
|
|
|
if (at != -1 && (at < found || found === -1)) { |
377
|
|
|
found = at; |
378
|
|
|
} |
379
|
|
|
} |
380
|
|
|
return found; |
381
|
|
|
}, |
382
|
|
|
|
383
|
|
|
|
384
|
|
|
indexOfAll: function(find, caseSensitive = true, startAt = 0, wholeWords = false){ |
385
|
|
|
var str = this; |
386
|
|
|
var indices = []; |
387
|
|
|
|
388
|
|
|
var len = str.length; |
389
|
|
|
var c = startAt; |
390
|
|
|
while (c < len) { |
391
|
|
|
c = str.smartIndexOf(find, caseSensitive, true, c, false, wholeWords); |
392
|
|
|
if (c === -1) { |
393
|
|
|
break; |
394
|
|
|
} |
395
|
|
|
indices.push(c); |
396
|
|
|
c += find.length; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
return indices; |
400
|
|
|
}, |
401
|
|
|
|
402
|
|
|
findAll: function(find){ |
403
|
|
|
var str = this.toString(); |
404
|
|
|
var matches = []; |
405
|
|
|
|
406
|
|
|
// if regex return all matches |
407
|
|
|
if (find.isRegex()){ |
408
|
|
|
do { |
409
|
|
|
var match = find.exec(str); |
410
|
|
|
if (match) { |
411
|
|
|
matches.push(match); |
412
|
|
|
} |
413
|
|
|
} while (match); |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
// if string find and return all matches |
417
|
|
|
if (find.isString()){ |
418
|
|
|
var indices = str.indexOfAll(); |
419
|
|
|
for (var i=0; i<indices.length; i++){ |
420
|
|
|
var index = indices[i]; |
421
|
|
|
var match = {startIndex:index, endIndex:index+find.length, text:find}; |
|
|
|
|
422
|
|
|
} |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
return matches; |
426
|
|
|
}, |
427
|
|
|
|
428
|
|
|
indexOfNth(search, nth, wholeWords = false, matchCase = true) { |
429
|
|
|
var text = this.toString(); |
430
|
|
|
|
431
|
|
|
// quickly test if text contains wanted var |
432
|
|
|
if (!matchCase || text.contains(search)) { |
433
|
|
|
|
434
|
|
|
// create regex to find |
435
|
|
|
var regex = UB.regex.New(search, wholeWords, matchCase); |
436
|
|
|
|
437
|
|
|
|
438
|
|
|
// find and return index if found |
439
|
|
|
var match = null; |
440
|
|
|
for (var n = 0; n < nth; n++) { |
441
|
|
|
match = regex.exec(text); |
442
|
|
|
if (match == null || match < 0) { |
443
|
|
|
return -1; |
444
|
|
|
} else { |
|
|
|
|
445
|
|
|
//startAt = match + 1; |
446
|
|
|
} |
447
|
|
|
} |
448
|
|
|
return match == null ? -1 : match; |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
return -1; |
452
|
|
|
}, |
453
|
|
|
|
454
|
|
|
|
455
|
|
|
none:null |
456
|
|
|
}; |
457
|
|
|
|
458
|
|
|
// register funcs |
459
|
|
|
UB.registerFuncs(String.prototype, stringFuncs); |